﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using foursquare.Location;

namespace foursquare
{
    /// <summary>
    /// Class to manage location events and GeoService location change notifications
    /// </summary>
    internal class LocationManager : IRunnable
    {
        private bool _running = false;
        private System.Windows.Forms.Timer _timer;
        private List<ILocationProvider> _locationProviders = new List<ILocationProvider>();
        private List<GeoService> _geoServices = new List<GeoService>();
        private GeoLocation _previousLocation;
        private Thread _thread;

        /// <summary>
        /// Initializes a new instance of the <see cref="LocationManager"/> class.
        /// </summary>
        public LocationManager()
        {
            _locationProviders.Add(new GpsLocationProvider());
            //_locationProviders.Add(new CellTowerLocationProvider());

            _timer = new System.Windows.Forms.Timer();
            _timer.Interval = 10000;
            _running = true;
            _timer.Tick += new EventHandler(_timer_Tick);

            Start();
        }

        private void _timer_Tick(object sender, EventArgs e)
        {
            _thread = new Thread(new ThreadStart(Notify));
            _thread.Start();
        }

        /// <summary>
        /// Checks each provider for a new location using GPS first, then Cell Tower data
        /// </summary>
        private void Notify()
        {
            // Get the current location
            foreach (var provider in _locationProviders)
            {
                GeoLocation location = provider.CurrentLocation;

                if (location != GeoLocation.Empty && location != _previousLocation)
                {
                    // Notify all services of a new location
                    NotifyLocationChanged(location);
                    // Prevent repeat notifications from the same location
                    _previousLocation = location;
                    break;
                }
            }
        }

        /// <summary>
        /// Notifies each GeoService implementation of a location change.
        /// </summary>
        /// <param name="location">The location.</param>
        private void NotifyLocationChanged(GeoLocation location)
        {
            _geoServices.ForEach(g => g.Update(location));
        }
        /// <summary>
        /// Attaches the specified GeoService.
        /// </summary>
        /// <param name="service">The service.</param>
        internal void Attach(GeoService service)
        {
            _geoServices.Add(service);

            if (_previousLocation != null)
            {
                service.Update(_previousLocation);
            }
        }
        /// <summary>
        /// Detatches the specified GeoService.
        /// </summary>
        /// <param name="service">The service.</param>
        internal void Detatch(GeoService service)
        {
            _geoServices.Remove(service);
        }
        /// <summary>
        /// Toggles the timer.
        /// </summary>
        private void ToggleTimer()
        {
            _timer.Enabled = _running;
        }
        /// <summary>
        /// Gets a value indicating whether this <see cref="LocationManager"/> is running.
        /// </summary>
        /// <value><c>true</c> if running; otherwise, <c>false</c>.</value>
        internal bool Running { get { return _running; } }

        #region IRunnable Members

        /// <summary>
        /// Starts this instance to notify location changes.
        /// </summary>
        public void Start()
        {
            _running = true;
            
            foreach (var provider in _locationProviders)
            {
                provider.Start();
            }

            ToggleTimer();
        }
        /// <summary>
        /// Stops this instance from updating location.
        /// </summary>
        public void Stop()
        {
            _running = false;
            
            ToggleTimer();
            
            foreach (var provider in _locationProviders)
            {
                provider.Stop();
            }
        }

        #endregion
    }
}
